package com.bestcem.xm.user.service.impl;

import com.bestcem.xm.common.core.sequence.dao.SequenceDao;
import com.bestcem.xm.common.core.sequence.entity.SequenceDO;
import com.bestcem.xm.common.core.sequence.entity.SequenceEntity;
import com.bestcem.xm.user.service.SequenceService;
import com.bestcem.xm.user.util.business.DataBaseUtil;
import com.bestcem.xm.user.util.business.UserCacheUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 自增长seq服务
 *
 * @author wangyunyun <yunyun.wang@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/11 17:56
 */
@Slf4j
@Service("userSequenceServiceImpl")
public class SequenceServiceImpl implements SequenceService {

    private static final int INCREMENT_STEP = 1000;

    @Autowired
    private SequenceDao sequenceDao;

    @Autowired
    private UserCacheUtil userCacheUtil;

    @Override
    public int incrementVersion(String key) {
        Boolean hasKey = userCacheUtil.hasKey(key);
        // 判断redis是否已存在
        Integer version;
        if (null != hasKey && hasKey) {
            version = Integer.valueOf(userCacheUtil.get(key));
        } else {
            // 不存在则从mysql中查询或者初始化
            return getVersionAndInitByMysql(key);
        }

        if (version % INCREMENT_STEP == 0) {
            // 说明上一次从mysql中取的结果已经被用完，需要重新在取一次
            sequenceDao.findOneAndUpdateByCodeAndSeqInc(key, INCREMENT_STEP);
        }
        // redis继续自增
        return userCacheUtil.incrBy(key).intValue();
    }

    /**
     * 从mysql中获取指定code对应的seq值
     * 如果没有则初始化一条seq从1开始的数据，同步塞入到redis缓存
     *
     * @param versionKey code
     * @return int
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/02/11 17:30
     */
    private int getVersionAndInitByMysql(String versionKey) {
        int version = 1;
        SequenceDO sequenceInfo = sequenceDao.findOneByCode(versionKey);
        if (null == sequenceInfo) {
            // 创建一条数据seq数据
            Date now = new Date();
            SequenceEntity entity = new SequenceEntity();
            entity.setSeq(INCREMENT_STEP);
            entity.setUpdateTime(now);
            entity.setCreateTime(now);
            entity.setIncrStep(INCREMENT_STEP);
            entity.setCode(versionKey);
            sequenceDao.findOneAndUpdateByCode(entity);
        } else {
            version = sequenceInfo.getSeq();
        }
        // 同步插入到redis中
        userCacheUtil.setIfAbsent(versionKey, version);
        return version;
    }

    @Override
    public void batchUpdateSeqByCode(HashMap<String, Integer> stringMap) {
        ArrayList<String> keys = new ArrayList<>();
        HashMap<String, Integer> seqMap = new HashMap<>();
        for (Map.Entry<String, Integer> entry : stringMap.entrySet()) {
            String key = entry.getKey();
            int value = entry.getValue();
            double ceil = Math.ceil((double) value / SequenceServiceImpl.INCREMENT_STEP);
            int val = (int) (ceil * SequenceServiceImpl.INCREMENT_STEP);

            keys.add(key);
            seqMap.put(key, val);
        }

        // 批量查询
        ArrayList<SequenceEntity> sequenceInfo = sequenceDao.listByCodes(keys);
        Map<String, SequenceEntity> sequenceMap = sequenceInfo.stream().collect(Collectors.toMap(SequenceEntity::getCode, Function.identity()));

        ArrayList<SequenceEntity> createList = new ArrayList<>();
        ArrayList<SequenceEntity> updateList = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : seqMap.entrySet()) {
            String key = entry.getKey();
            Integer val = entry.getValue();
            SequenceEntity sequence = sequenceMap.get(key);
            if (Objects.isNull(sequence)) {
                // 创建一条数据seq数据
                SequenceEntity entity = new SequenceEntity();
                Date now = new Date();
                entity.setId(DataBaseUtil.generateId());
                entity.setSeq(val);
                entity.setUpdateTime(now);
                entity.setCreateTime(now);
                entity.setIncrStep(INCREMENT_STEP);
                entity.setCode(key);
                createList.add(entity);
                log.info("sequence创建数据 key:{},seq:{}", key, val);
            } else if (!sequence.getSeq().equals(val)) {
                SequenceEntity entity = new SequenceEntity();
                entity.setId(sequence.getId());
                entity.setSeq(entry.getValue());
                updateList.add(entity);
                log.info("sequence更新数据 key:{},seq:{}", key, val);
            }
        }

        // 批量新增
        if (CollectionUtils.isNotEmpty(createList)) {
            sequenceDao.batchCreate(createList);
        }
        // 批量更新
        if (CollectionUtils.isNotEmpty(updateList)) {
            sequenceDao.batchUpdateSeq(updateList);
        }
    }

}
